package com.example.camera;

import java.io.Console;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import android.R.integer;
import android.content.Context;
import android.graphics.Bitmap;
import android.media.Image;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class OpenCVPreview extends android.view.SurfaceView implements SurfaceHolder.Callback {

	private static final String TAG = OpenCVPreview.class.getSimpleName();
	
	private Handler calculateHandler;
	protected Bitmap bitmap;
	protected DrawThread drawThread;
	
	public OpenCVPreview(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		getHolder().addCallback(this);
		
		calculateHandler = new Handler() {
			@Override
			public void handleMessage(Message msg){
				super.handleMessage(msg);
				calculate(msg.arg1, msg.arg2, (byte[]) msg.obj);
			};
		};
		
		// TODO Auto-generated constructor stub
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Log.i(TAG, "surfaceCreated");
		drawThread = new DrawThread(getHolder(), getResources());
		drawThread.setRunning(true);
		drawThread.start();
		
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.i(TAG, "surfaceDestroyed");
		boolean retry = true;
		drawThread.setRunning(false);
		while (retry)
		{
			try
			{
				drawThread.join();
				retry = false;	
			}
			catch (InterruptedException e)
			{
				Log.e(TAG, "Error: surfaceDestroyed", e);
			}
			
		}
	}
	
	protected void calculate(int width, int height, byte[] data)
	{
		Mat mYuv = new Mat(height + height / 2, width, CvType.CV_8UC1);
		mYuv.put(0, 0, data);		
		// crop image
		Integer halfWidth = width / 2;
		Integer HalfHeight = height / 2;
		Integer startX = halfWidth - (halfWidth / 2);
		Mat mRgba = new Mat(height, width, CvType.CV_8UC1);
		Mat thresholdImage = new Mat(mRgba.size(), CvType.CV_8UC1);
		
		Rect roi = new Rect(0, HalfHeight, width, height-HalfHeight);
//	    mRgba.copyTo(mRgba.submat(roi));
	    mRgba.submat(roi);
		//Mat cropped = new Mat(mRgba, roi);
//		cropped.copyTo(mRgba);
//		mRgba = roi.clone();
		Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420p2BGR, 4);
		//convert to grayscale
		//Imgproc.cvtColor(mRgba, thresholdImage, Imgproc.COLOR_mRGBA2RGBA, 4);
//		Imgproc.medianBlur(mRgba, mRgba, 5);
//		 Perform a Gaussian blur (convolving in 5x5 Gaussian) & detect edges
        Imgproc.GaussianBlur(mRgba, mRgba, new Size(5,5), 2.2, 2);
		Imgproc.Canny(mRgba, thresholdImage, VActivity.CANNY_MIN_THRESHOLD, VActivity.CANNY_MAX_THRESHOLD);
		Mat lines = new Mat();
		
		double rho = 1;
		double theta = Math.PI/180;
		int threshold = 50;
		
		//do Hough transform to find lanes
		Imgproc.HoughLinesP(thresholdImage, lines, rho, theta, threshold, VActivity.HOUGH_MIN_LINE_LENGTH, VActivity.HOUGH_MAX_LINE_GAP);
		for (int x = 0; x < lines.cols(); x++)
		{
			double[] vec = lines.get(0, x);
			double x1 = vec[0],
					y1 = vec[1],
					x2 = vec[2],
					y2 = vec[3];
			Point start = new Point(x1, y1);
			Point end = new Point(x2, y2);
			
			double dx = x2 - x1;
			double dy = y2 - y1;
			
			double angle = Math.atan2(dy, dx) * 180 / Math.PI;
			Log.i(VActivity.TAG, Double.toString(angle));
			
			if (Math.abs(angle) <= VActivity.LINE_REJECT_DEGREES)
			{
				Log.i(VActivity.TAG, "Reject: " + Double.toString(angle));
				// reject near horizontal lines
				continue;
			}
			Core.line(mRgba, start, end, new Scalar(255, 0, 0), 3);
		}
		
		if (bitmap == null)
			bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		
		Utils.matToBitmap(mRgba, bitmap);
		            			
		drawThread.setBitmap(bitmap);
	}
	
	public Handler getCalculateHandler()
	{
		return calculateHandler;
	}
	
}
